GNU make (その2)
GNU makeですが、分割したソースファイルの数が多くなってきますとソースファイルとオブジェクトファイルを別々のフォルダにしたくなってくると思います。
そこで、ソースファイルを格納するフォルダとオブジェクトファイルを格納するフォルダを分けた上でターゲットファイルをカレントフォルダに作成するmakefileをご紹介します。
makefileスケルトン(makefile2※注)
#ソースファイル(すべて列挙します) #ここでは例として main.c と sub.c の2つを列挙しています。 SRC=main.c sub.c SRCS=$(addprifix $(SRCDIR),$(SRC)) SRCDIR=src/ #オブジェクトファイル OBJ = $(SRC:.c=.o) OBJS=$(addprefix $(OBJDIR), $(OBJ)) OBJDIR=obj/ #作成する実行ファイル TARGET=target.exe #Cコンパイラ CC=gcc #コンパイルオプション #CFLAGS=-Wall -O3 #-Wall はワーニングを表示、 -O3 は最適化オプション CFLAGS= #リンクオプション #LDFLAGS=-mwindows #削除コマンド RM=rm #分割コンパイル(オブジェクトファイル作成) # $@ ターゲットファイル(ここではオブジェクトファイル)名 # $< 最初の依存関係の名前 $(OBJDIR)%.o: $(SRCDIR)%.c $(SRCDIR)%.h $(CC) $(CFLAGS) -o $@ -c $< #デフォルトターゲット .PHONY : all all: $(TARGET) # リンク # $@ ターゲットファイル(ここでは target.exe)名 $(TARGET): $(OBJS) $(CC) $(OBJS) $(LDFLAGS) -o $@ #オブジェクトファイルをすべて削除 .PHONY : clean clean: $(RM) $(OBJS)
※注 メイクファイルのファイル名は通常 makefile とし、拡張子は付けません。 理由はデフォルトファイル名が拡張子なしの makefile で、makeと入力すれば(makeを実行すれば)カレントディレクトリの makefile が読み込まれ、実行されるためです。
ちょこっと解説します。
- 最終的に作成したいファイルは TARGET で示される target.exe(実行ファイル)です。
- ソースファイルはカレントフォルダのサブフォルダ(src/)に格納されていて、オブジェクトファイルもまたサブフォルダの(obj/)に格納するものとしています。
- TARGET を作成するために必要なファイルは「リンク」のところで示される OBJS で、
OBJS はソースファイル(拡張子 .c)を .o に変更して更にOBJDIRで示されたサブフォルダに格納するファイルになります。
- .c ファイルは SRC で示される main.c と sub.c になります。
ソースファイル名が異なる場合には適宜書き換えて下さい。
また、もっとたくさんのソースファイルがある場合にはそれを追加してください。
- SRCSはSRCで示される各ソースファイルにサブフォルダ名を付けたものになります。 「addprefix」はMakefileの関数で、ここでは各ソースファイル名にサブフォルダ名を連結しています。
- 「分割コンパイル(オブジェクトファイル作成)」のところで、
$(OBJDIR)%.o: $(SRCDIR)%.c $(SRCDIR)%.h
と記述していますが、これは、
src/main.c src/main.h src/sub.c src/sub.h
というソースファイルとヘッダーファイルがあって、main.c内ではmain.hをインクルードしていて、 sub.c内ではsub.hをインクルードしているものとして記述しています。 もし仮に、ヘッダーファイルが1つ(header.h)しかないという場合には、
$(OBJDIR)%.o: $(SRCDIR)%.c $(SRCDIR)header.h
と記述すればOKです。
(makefile2をmakefileにリネームした上で)make[Enter]
と入力すればコンパイル・リンクが実行され、実行ファイルが作成されます(エラーがなければですが...)。
make clean[Enter]
と入力すればオブジェクトファイルがすべて削除されます。
以上、非常に簡単な解説でしたがお分かり頂けたでしょうか?
なんとなく分かったら実際にやってみるとよいでしょう。
補足:「削除コマンド」についてですが、コマンドプロンプトで走るMinGWの場合はdelコマンド、
そうでない場合はrmコマンドを指定します。
どちらのコマンドも実行可能である場合にはどちらでも構いません。